package com.minidb.sql_compiler;

import com.minidb.utils.Condition;
import com.minidb.utils.StatementType;
import com.minidb.utils.TokenType;

import java.util.ArrayList;
import java.util.List;

public class SyntaxParser {
    private List<Token> toks;
    private int pos;

    public SQLStatement parse(String sql) {
        LexicalAnalyzer lex = new LexicalAnalyzer();
        toks = lex.tokenize(sql);
        pos = 0;
    
        Token first = peek();
        SQLStatement stmt;
        if (is(first,"SELECT")) stmt = parseSelect();
        else if (is(first,"CREATE")) stmt = parseCreate();
        else if (is(first,"INSERT")) stmt = parseInsert();
        else if (is(first,"DELETE")) stmt = parseDelete();
        else throw synErr(first, "SELECT/CREATE/INSERT/DELETE");
    
        // 允许可选的分号
        if (isSym(";")) {
            next(); // 消费分号
        }
        expect(TokenType.EOF, null); // 必须读到结束
        return stmt;
    }

    private SQLStatement parseSelect() {
        expectKw("SELECT");
        List<String> cols = new ArrayList<>();
        if (isSym("*")) next(); else {
            cols.add(ident("列名"));
            while (isSym(",")) { next(); cols.add(ident("列名")); }
        }
        expectKw("FROM");
        String table = ident("表名");
        Condition cond = null;
        if (isKw("WHERE")) { next(); cond = condition(); }

        SQLStatement s = new SQLStatement();
        s.type = StatementType.SELECT; s.tableName = table; s.columns = cols; s.condition = cond;
        return s;
    }

    private SQLStatement parseCreate() {
        expectKw("CREATE"); expectKw("TABLE");
        String table = ident("表名");
        expectSym("(");
        List<String> cols = new ArrayList<>(), types = new ArrayList<>();
        cols.add(ident("列名"));
        String ty = ident("类型");
        if (isSym("(")) { next(); String len = number("类型长度"); expectSym(")"); ty = ty + "(" + len + ")"; }
        types.add(ty);
        while (isSym(",")) {
            next();
            cols.add(ident("列名"));
            ty = ident("类型");
            if (isSym("(")) { next(); String len = number("类型长度"); expectSym(")"); ty = ty + "(" + len + ")"; }
            types.add(ty);
        }
        expectSym(")");

        SQLStatement s = new SQLStatement();
        s.type = StatementType.CREATE_TABLE; s.tableName = table; s.columns = cols; s.columnTypes = types;
        return s;
    }

    private SQLStatement parseInsert() {
        expectKw("INSERT"); expectKw("INTO");
        String table = ident("表名");
        List<String> cols = new ArrayList<>();
        if (isSym("(")) {
            next();
            cols.add(ident("列名"));
            while (isSym(",")) { next(); cols.add(ident("列名")); }
            expectSym(")");
        }
        expectKw("VALUES");
        expectSym("(");
        List<String> vals = new ArrayList<>();
        vals.add(value());
        while (isSym(",")) { next(); vals.add(value()); }
        expectSym(")");
    
        SQLStatement s = new SQLStatement();
        s.type = StatementType.INSERT; s.tableName = table; s.columns = cols; s.values = vals;
        return s;
    }

    private SQLStatement parseDelete() {
        expectKw("DELETE"); expectKw("FROM");
        String table = ident("表名");
        Condition cond = null;
        if (isKw("WHERE")) { next(); cond = condition(); }
        SQLStatement s = new SQLStatement();
        s.type = StatementType.DELETE; s.tableName = table; s.condition = cond;
        return s;
    }

    private Condition condition() {
        String col = ident("列名");
        Token opTok = next(); // 可能为 < <= <> 之类
        String op = opTok.lexeme;
        if ((op.equals("<") || op.equals(">") || op.equals("!")) && isSym("=")) op += next().lexeme;
        else if (op.equals("<") && isSym(">")) op += next().lexeme; // <>
        String val = value();
        return new Condition(col, op, val);
    }

    // ———— 基础读取 ————
    private String value() {
        Token t = peek();
        
        // 处理负数
        boolean isNegative = false;
        if (isSym("-")) {
            next(); // 消费负号
            isNegative = true;
            t = peek(); // 重新获取下一个token
        }
        
        if (t.type == TokenType.CONST_STRING) {
            if (isNegative) {
                throw synErr(t, "负号不能用于字符串");
            }
            next();
            return "'" + t.lexeme + "'";
        } else if (t.type == TokenType.CONST_NUMBER) {
            String number = next().lexeme;
            return isNegative ? "-" + number : number;
        } else if (isKw("NULL")) {
            if (isNegative) {
                throw synErr(t, "负号不能用于NULL");
            }
            next();
            return "NULL";
        } else if (isKw("TRUE")) {
            if (isNegative) {
                throw synErr(t, "负号不能用于布尔值");
            }
            next();
            return "TRUE";
        } else if (isKw("FALSE")) {
            if (isNegative) {
                throw synErr(t, "负号不能用于布尔值");
            }
            next();
            return "FALSE";
        } else {
            throw synErr(t, "字面量、NULL或布尔值");
        }
    }

    private String ident(String what) {
        Token t = next();
        if (t.type == TokenType.IDENTIFIER) return t.lexeme;
        throw synErr(t, what);
    }

    private String number(String what) {
        Token t = next();
        if (t.type == TokenType.CONST_NUMBER) return t.lexeme;
        throw synErr(t, what);
    }

    // ———— 帮助方法 ————
    private Token peek() { return toks.get(pos); }
    private Token next() { return toks.get(pos++); }

    private boolean is(Token tok, String kwUpper) {
        return tok.type == TokenType.KEYWORD && tok.lexeme.equalsIgnoreCase(kwUpper);
    }
    private boolean isKw(String kwUpper) { return is(peek(), kwUpper); }
    private boolean isSym(String s) { Token t=peek(); return t.type==TokenType.DELIMITER||t.type==TokenType.OPERATOR ? t.lexeme.equals(s) : false; }

    private void expectKw(String kwUpper) { Token t = next();
        if (!(t.type==TokenType.KEYWORD && t.lexeme.equalsIgnoreCase(kwUpper))) throw synErr(t, kwUpper);
    }
    private void expectSym(String s) { Token t = next();
        if (!((t.type==TokenType.DELIMITER||t.type==TokenType.OPERATOR) && t.lexeme.equals(s))) throw synErr(t, s);
    }
    private void expect(TokenType type, String show) {
        Token t = next();
        if (t.type != type) throw synErr(t, show==null?type.name():show);
    }

    private IllegalArgumentException synErr(Token got, String expect) {
        String exp = expect==null? "" : "，期望 " + expect;
        return new IllegalArgumentException("语法错误 @(" + got.line + "," + got.col + "): 得到 '" + got.lexeme + "'" + exp);
    }
}
